#ifndef LHC_BUFFERED_STREAM_H_INCLUDED_
#define LHC_BUFFERED_STREAM_H_INCLUDED_

#include "IStream.h"
#include "Macros.h"
#include <boost/shared_ptr.hpp>
#include <boost/cstdint.hpp>
#include <boost/noncopyable.hpp>
#include <vector>

namespace lhcutils
{

// NOTE: If both reading and writing to the stream, the underlying stream must be seekable.
class BufferedStream : public IStream, private boost::noncopyable
{
private:
	boost::shared_ptr<IStream> m_stream;

	std::vector<boost::uint8_t> m_buffer;

	// When writing, this is the number of bytes in the buffer unwritten to the underlying stream.
	// When reading, this is the total number of valid bytes in the buffer.
	size_t m_bytesInBuffer; 

	// Invariant: When writing, the "real" stream position = underlying stream position + m_bufferPos
	// Invariant: When reading, the "real" stream position = underlying stream position - m_bytesInBuffer + m_bufferPos
	size_t m_bufferPos; 

	bool m_reading;

	boost::int64_t GetOffsetFromUnderlyingStreamPosition();
	size_t GetBufferSize();

public:
	BufferedStream(boost::shared_ptr<IStream> stream, boost::int32_t bufferSize = 4096);

	virtual void Close() OVERRIDE;
	virtual ~BufferedStream();

	virtual bool CanRead() OVERRIDE;
	virtual bool CanWrite() OVERRIDE;
	virtual bool CanSeek() OVERRIDE;
	
	// Throws: IoException, NotSupportedException, other ProgrammerErrorException
	virtual boost::int64_t GetPosition() OVERRIDE;

	// Throws: IoException, NotSupportedException, other ProgrammerErrorException
	virtual void SetPosition(boost::int64_t newPosition, SeekOrigin::Value origin) OVERRIDE;

	// Throws: IoException
	virtual void Flush() OVERRIDE;

	// Throws: IoException, NotSupportedException, other ProgrammerErrorException
	virtual size_t Read(void* buffer, size_t count) OVERRIDE;

	// Throws: IoException, NotSupportedException, other ProgrammerErrorException
	virtual void Write(const void* buffer, size_t count) OVERRIDE;
};

}

#endif

/*
 Copyright 2011 Greg Najda

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
